package com.zy.example.config;
import com.zy.example.filter.SmsCodeFilter;
import com.zy.example.filter.ValidateCodeFilter;
import com.zy.example.service.CustomUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;

/**
 * spring security配置类
 *
 * @author zy
 * @since 2020-2-9
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationSuccessHandler authenticationSucessHandler;

    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    private ValidateCodeFilter validateCodeFilter;

    @Autowired
    private SmsCodeFilter smsCodeFilter;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    private SmsAuthenticationConfig smsAuthenticationConfig;

    @Autowired
    private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;

    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    /**
     * 配置拦截请求资源
     * @param http：HTTP请求安全处理
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加图片验证码校验过滤器
                .addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)  // 添加手机短信验证码校验过滤器
                .authorizeRequests()    // 授权配置
                .antMatchers("/code/image","/code/sms","/session/invalid","/signout/success")
                .permitAll()       // 无需认证的请求路径
                .anyRequest()       // 任何请求
                .authenticated()    //都需要身份认证
                .and()
                .formLogin()         // 或者httpBasic()
                .loginPage("/login")  // 指定登录页的路径
                //我们的form表单action是将请求提交到/login/mobile页面，而在Spring Security中配置的 .loginProcessingUrl("/login") 值为/login，这两者为什么不一样呢？这样做的目的是通过指定Spring Security中的UsernamePasswordAuthenticationFilter的拦截目标为post请求/login，从而使得该过滤器不会拦截/login/mobile请求；那么针对/login/mobile请求我们会仿照UsernamePasswordAuthenticationFilter定义自己的过滤器，然后对其进行认证；
                .loginProcessingUrl("/login")  // 指定自定义form表单提交请求的路径
                .successHandler(authenticationSucessHandler)    // 处理登录成功
                .failureHandler(authenticationFailureHandler) // 处理登录失败
                // 必须允许所有用户访问我们的登录页（例如未验证的用户，否则验证流程就会进入死循环）
                // 这个formLogin().permitAll()方法允许所有用户基于表单登录访问/login这个page。
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/signout")
                //.logoutSuccessUrl("/signout/success")
                .logoutSuccessHandler(logoutSuccessHandler)   //处理退出成功  替代logoutSuccessUrl
                .deleteCookies("JSESSIONID")
//                .and()
//                .rememberMe()
//                .tokenRepository(persistentTokenRepository)  // 配置 token 持久化仓库
//                .tokenValiditySeconds(3600)      // remember 过期时间，单为秒
//                .userDetailsService(userDetailsService)   // 处理自动登录逻辑
//                .and()
//                .logout()
//                .permitAll()
                .and()
                //默认都会产生一个hiden标签 里面有安全相关的验证 防止请求伪造 这边我们暂时不需要 可禁用掉
                .csrf().disable()
                .apply(smsAuthenticationConfig) // 将短信验证码认证配置加到 Spring Security 中  添加一个安全配置其到http的configurers集合
                .and()
                .sessionManagement()    //添加session管理器
                //.invalidSessionUrl("/session/invalid")   //Session失效后跳转到这个链接
                .maximumSessions(1)
                .maxSessionsPreventsLogin(true)
                .expiredSessionStrategy(sessionInformationExpiredStrategy);
    }
}
